/*
* Copyright (c) 2025 Huawei Device Co., Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including but not limited to the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to provide persons with access to the Software
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGE OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

import { navigationProperty, NavigationMode, PageType, NavBarPosition } from '../../types/navigation/index';
import { defaultConfig } from './default/index';
import { EventManager } from '../../hooks/eventManager/index';
import { getLengthNum, isValidLength, getFinalLength } from '../../utils/index';
import { CallbackFunc } from '../../types/eventManager';

/**
 * @description 基于web components实现分栏组件容器标签
 */
export class NavigationComponent extends HTMLElement {
  private _property: string[] = navigationProperty;
  private _styleElement: HTMLStyleElement | null;
  private _containerWidth = 0;
  private _boundaryWidth = 600;
  private _resizeObserver: ResizeObserver | null = null;
  private _eventManager: EventManager = new EventManager(this);
  private _isDragging = false;
  private _isDragged = false;
  private _lastPosition = 0;
  private _dragBarWidth = 1;
  private _enableDrag = true;
  private _isMounted = false;

  private _scopeId = '';
  private _mode: NavigationMode = defaultConfig.mode;
  private _currentMode: NavigationMode = defaultConfig.mode;
  private _pageType: PageType | null = null;
  private _navBarWidth = 0;
  private _originNavBarWidth = 0;
  private _isNavBarWidthSet = false;
  private _navBarWidthRange: number[] = [];
  private _isNavBarWidthRangeSet = false;
  private _minContentWidth = 0;
  private _isMinContentWidthSet = false;
  private _minCalcContentWidth = 0;
  private _navBarPosition: NavBarPosition = NavBarPosition.Start;
  private _dividerDom: HTMLElement | null = null;

  constructor() {
    super();
    this._styleElement = null;
  }

  // 注册导航栏显示状态切换回调
  registerStateChangeEvent(callback: CallbackFunc): void {
    this._eventManager.on('onNavBarStateChange', callback);
  }

  // 注册单双栏状态变化回调
  registerModeChangeEvent(callback: CallbackFunc): void {
    this._eventManager.on('onNavigationModeChange', callback);
  }

  // 获取容器尺寸
  private _getContainerSize(): void {
    this._containerWidth = this.offsetWidth;
  }

  // 创建分割线元素
  private _createDivider(): void {
    const firstChild = this.firstElementChild;
    const dividerElement = document.createElement('div');
    dividerElement.classList.add(`${this._scopeId}-divider`);
    if (firstChild) {
      this.insertBefore(dividerElement, firstChild.nextSibling);
    } else {
      throw new Error('No valid child elements.');
    }
  }

  // 分割线拖拽开始回调
  private _dragStartCallback() {
    return (e: TouchEvent): void => {
      this._lastPosition = e.touches[0].clientX;
      this._isDragging = true;
    };
  }

  // 分割线拖拽过程回调
  private _dragMoveCallback() {
    return (e: TouchEvent): void => {
      if (!this._isDragging) {
        return;
      }
      const currentX = e.touches[0].clientX;
      const diff = this._navBarPosition === NavBarPosition.Start ? currentX - this._lastPosition : this._lastPosition - currentX;
      const minNavBarWidth = this._navBarWidthRange[0];
      const maxNavBarWidth = Math.min(this._navBarWidthRange[1], this._containerWidth - this._minContentWidth - this._dragBarWidth);
      if (this._navBarWidth + diff >= minNavBarWidth && this._navBarWidth + diff <= maxNavBarWidth) {
        this._lastPosition = currentX;
        this._navBarWidth = this._navBarWidth + diff;
        this._originNavBarWidth = this._navBarWidth;
        this._attachStyles();
      }
    };
  }

  // 分割线拖拽结束回调
  private _dragEndCallback() {
    return (): void => {
      this._isDragging = false;
      this._isDragged = true;
    };
  }

  // 初始化分割线拖拽事件
  private _setupDragEvents(): void {
    this._dividerDom = this.querySelector(`.${this._scopeId}-divider`);
    this._dividerDom?.addEventListener('touchstart', this._dragStartCallback());
    this._dividerDom?.addEventListener('touchmove', this._dragMoveCallback());
    this._dividerDom?.addEventListener('touchend', this._dragEndCallback());
  }

  // 刷新组件属性和样式
  private _updatComponentState(): void {
    requestAnimationFrame(() => {
      this._getContainerSize();
      this._refreshProperty();
      this._attachStyles();
    });
  }

  // 初始化容器尺寸监听
  private _setupResizeObserver(): void {
    this._resizeObserver = new ResizeObserver(entris => {
      for (const entry of entris) {
        if (entry.target === this) {
          this._updatComponentState();
        }
      }
    });
    this._resizeObserver.observe(this);
  }

  // 自定义元素第一次被连接到文档DOM时被调用
  connectedCallback(): void {
    requestAnimationFrame(() => {
      this._scopeId = this.getAttribute('scope') || '';
      this._createDivider();
      this._getContainerSize();
      this._setProperty();
      this._originNavBarWidth = this._navBarWidth;
      this._attachStyles();
      this._setupDragEvents();
      this._setupResizeObserver();
      const eventTimer = setTimeout(() => {
        this._eventManager.emit('onNavBarStateChange', this._pageType === PageType.Navbar || this._pageType === PageType.None);
        this._eventManager.emit('onNavigationModeChange', this._currentMode);
        clearTimeout(eventTimer);
      }, 10);
      this._isMounted = true;
    });
  }

  // 自定义元素与文档DOM断开连接时被调用
  disconnectedCallback(): void {
    this._dividerDom?.removeEventListener('touchstart', this._dragStartCallback());
    this._dividerDom?.removeEventListener('touchmove', this._dragMoveCallback());
    this._dividerDom?.removeEventListener('touchend', this._dragEndCallback());
    this._resizeObserver?.unobserve(this);
    this._resizeObserver = null;
    this._dividerDom = null;
  }

  // 定义监听属性范围
  static get observedAttributes(): string[] {
    return navigationProperty;
  }

  // 自定义元素的属性被增加、移除或更改时被调用
  attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {
    if (this._property.includes(name) && oldValue !== newValue) {
      this._setProperty();
      this._attachStyles();
    }
  }

  // 更新minContentWidth属性
  private _updateMinContentWidth(minContentWidth: string | null): void {
    if (!minContentWidth) {
      this._isMinContentWidthSet = false;
      this._minContentWidth = 0;
      this._minCalcContentWidth = defaultConfig.minContentWidth;
    } else if (!isValidLength(minContentWidth) || getLengthNum(minContentWidth) < 0) {
      this._isMinContentWidthSet = true;
      this._minContentWidth = defaultConfig.minContentWidth;
      this._minCalcContentWidth = defaultConfig.minContentWidth;
    } else {
      this._isMinContentWidthSet = true;
      this._minContentWidth = getFinalLength(minContentWidth, this._containerWidth);
      this._minCalcContentWidth = getFinalLength(minContentWidth, this._containerWidth);
    }
  }

  // 更新navBarWidthRange属性
  private _updateNavBarWidthRange(initNavBarWidthRange: string | null): void {
    const defaultNavBarWidthRange = [defaultConfig.minNavBarWidth, Math.max(defaultConfig.minNavBarWidth, Math.min(this._containerWidth * 0.4, 432))];
    if (!initNavBarWidthRange || initNavBarWidthRange === 'null') {
      this._isNavBarWidthRangeSet = false;
      this._navBarWidthRange = defaultNavBarWidthRange;
    } else {
      this._isNavBarWidthRangeSet = true;
      const navBarWidthRange = JSON.parse(initNavBarWidthRange);
      if (navBarWidthRange.length !== 2) {
        throw new Error('Invalid navBarWidthRange parameter.');
      } else {
        let minNavBarWidth = navBarWidthRange[0];
        let maxNavBarWidth = navBarWidthRange[1];
        if (!minNavBarWidth && minNavBarWidth !== 0 || !isValidLength(String(minNavBarWidth))) {
          minNavBarWidth = defaultConfig.minNavBarWidth;
        } else if (getLengthNum(String(minNavBarWidth)) < 0) {
          minNavBarWidth = 0;
        } else {
          minNavBarWidth = getFinalLength(String(minNavBarWidth), this._containerWidth);
        }

        if (!maxNavBarWidth && maxNavBarWidth !== 0 || !isValidLength(String(maxNavBarWidth))) {
          maxNavBarWidth = Math.min(this._containerWidth * 0.4, 432);
        } else if (getLengthNum(String(maxNavBarWidth)) < 0) {
          maxNavBarWidth = 0;
        } else {
          maxNavBarWidth = getFinalLength(String(maxNavBarWidth), this._containerWidth);
        }

        this._navBarWidthRange = [minNavBarWidth, Math.max(minNavBarWidth, maxNavBarWidth)];
      }
    }
  }

  // 更新navBarWidth属性
  private _updateNavBarWidth(navBarWidth: string | null): void {
    this._isNavBarWidthSet = !!navBarWidth;
    this._enableDrag = !this._isNavBarWidthSet || this._isNavBarWidthRangeSet || this._isMinContentWidthSet;
    if (!this._isDragged || !this._enableDrag) {
      if (!navBarWidth || !isValidLength(navBarWidth) || getLengthNum(navBarWidth) < 0) {
        this._navBarWidth = defaultConfig.navBarWidth;
      } else {
        this._navBarWidth = getFinalLength(navBarWidth, this._containerWidth);
      }
    }
    const remainingWidth = this._containerWidth - this._minContentWidth - this._dragBarWidth;
    // 只设置navBarWidth时
    if (!this._enableDrag) {
      this._navBarWidthRange = [Math.min(this._navBarWidth, remainingWidth), Math.min(this._navBarWidth, remainingWidth)];
    }
    // 基于组件剩余空间调整navBarWidth的值
    if (this._currentMode === NavigationMode.Split) {
      if (this._navBarWidth < this._navBarWidthRange[0]) {
        this._navBarWidth = this._navBarWidthRange[0];
      } else if (this._navBarWidth > this._navBarWidthRange[1]) {
        if (remainingWidth > this._navBarWidthRange[1]) {
          this._navBarWidth = this._navBarWidthRange[1];
        } else if (remainingWidth < this._navBarWidthRange[0]) {
          this._navBarWidth = this._navBarWidthRange[0];
        } else {
          this._navBarWidth = remainingWidth;
        }
      } else if (this._navBarWidth >= this._navBarWidthRange[0] && this._navBarWidth <= this._navBarWidthRange[1]) {
        if (remainingWidth <= this._navBarWidthRange[0]) {
          this._navBarWidth = this._navBarWidthRange[0];
        } else if (remainingWidth > this._navBarWidthRange[0] && remainingWidth <= this._navBarWidth) {
          this._navBarWidth = remainingWidth;
        }
      }
    }
  }

  // 更新mode属性(初始/容器缩放)
  private _updateNavigationMode(mode: string | null): void {
    this._mode = mode as NavigationMode;
    if (mode === NavigationMode.Auto) {
      const boundaryWidth = this._enableDrag ? this._minCalcContentWidth + this._navBarWidthRange[0] : this._boundaryWidth;
      const currentMode = this._containerWidth < boundaryWidth ? NavigationMode.Stack : NavigationMode.Split;
      if (this._isMounted && currentMode !== this._currentMode) {
        this._eventManager.emit('onNavigationModeChange', currentMode);
      }
      this._currentMode = currentMode;
    } else {
      if (this._isMounted && this._mode !== this._currentMode) {
        this._eventManager.emit('onNavigationModeChange', this._mode);
      }
      this._currentMode = this._mode;
    }
  }

  // 更新pageType属性(导航栏/内容区)
  private _updatePageType(pageType: string | null): void {
    if (this._currentMode === NavigationMode.Stack) {
      if (this._isMounted && pageType !== this._pageType) {
        if (this._pageType === PageType.None) {
          pageType === PageType.Content && this._eventManager.emit('onNavBarStateChange', false);
        } else if (pageType === PageType.Navbar) {
          this._eventManager.emit('onNavBarStateChange', true);
        } else if (pageType === PageType.Content) {
          this._eventManager.emit('onNavBarStateChange', false);
        }
      }
      this._pageType = pageType as PageType;
    } else {
      if (this._isMounted && this._pageType !== PageType.None && this._pageType === PageType.Content) {
        this._eventManager.emit('onNavBarStateChange', true);
      }
      this._pageType = PageType.None;
    }
  }

  // 元素属性赋值
  private _setProperty(): void {
    // 设置minContentWidth
    const minContentWidth = this.getAttribute('min-content-width');
    this._updateMinContentWidth(minContentWidth);

    // 设置navBarWidthRange
    const initNavBarWidthRange = this.getAttribute('nav-bar-width-range');
    this._updateNavBarWidthRange(initNavBarWidthRange);

    // 设置navBarWidth
    const navBarWidth = this.getAttribute('nav-bar-width');
    this._updateNavBarWidth(navBarWidth);

    // 设置mode
    const mode = this.getAttribute('mode') || defaultConfig.mode;
    this._updateNavigationMode(mode);

    // 设置页面类型
    const pageType = this.getAttribute('page-type');
    this._updatePageType(pageType);

    // 设置sideBarPosition
    const navBarPosition = this.getAttribute('nav-bar-position');
    this._navBarPosition = (navBarPosition || defaultConfig.navBarPosition) as NavBarPosition;
  }

  // 容器尺寸变化时, 刷新元素属性和组件状态
  private _refreshProperty(): void {
    // 更新minContentWidth
    const minContentWidth = this.getAttribute('min-content-width');
    this._currentMode === NavigationMode.Split && this._updateMinContentWidth(minContentWidth);

    // 更新navBarWidthRange
    const initNavBarWidthRange = this.getAttribute('nav-bar-width-range');
    this._currentMode === NavigationMode.Split && this._updateNavBarWidthRange(initNavBarWidthRange);

    // 更新mode
    this._updateNavigationMode(this._mode);

    // 更新navBarWidth
    const navBarWidth = this.getAttribute('nav-bar-width');
    if (this._currentMode === NavigationMode.Split) {
      this._updateNavBarWidth(navBarWidth);
      const remainingWidth = this._containerWidth - this._minContentWidth - this._dragBarWidth;
      if (remainingWidth <= this._originNavBarWidth && remainingWidth >= this._navBarWidthRange[0]) {
        this._navBarWidth = remainingWidth;
      }
      if (remainingWidth > this._originNavBarWidth) {
        this._navBarWidth = this._originNavBarWidth;
      }
      if (remainingWidth < this._navBarWidthRange[0] && this._containerWidth >= this._navBarWidthRange[0]) {
        this._navBarWidth = this._navBarWidthRange[0];
      }
    }

    // 更新页面类型
    const pageType = this.getAttribute('page-type');
    this._updatePageType(pageType);
  }

  // 添加样式
  private _attachStyles(): void {
    if (this._styleElement) {
      this._styleElement.remove();
    }

    const style = document.createElement('style') as HTMLStyleElement;
    style.textContent = `
      .${this._scopeId} {
        display: flex;
        width: 100%;
        height: 100%;
        flex-direction: ${this._navBarPosition === NavBarPosition.Start ? 'row' : 'row-reverse'};
        overflow: hidden;
      }

      .${this._scopeId} .${this._scopeId}-divider {
        position: relative;
        width: 1px;
        min-width: 1px;
        height: 100%;
        background-color: rgb(221, 223, 225);
        ${this._currentMode === NavigationMode.Stack ? 'display: none;' : ''}
      }

      .${this._scopeId} .${this._scopeId}-divider:before {
        content: '';
        position: absolute;
        top: 0;
        height: 100%;
        left: -2px;
        width: 5px;
        cursor: move;
      }

      .${this._scopeId} > multi-nav-bar {
        overflow: hidden;
        ${this._pageType === PageType.Navbar ? 'width: 100%;' : ''}
        ${this._pageType === PageType.Content ? 'display: none;' : ''}
        ${this._pageType === PageType.None ?
          `width: ${this._navBarWidth}px;
           min-width: ${this._navBarWidthRange[0]}px;
           max-width: ${this._navBarWidthRange[1]}px;` : ''
        }
      }

      .${this._scopeId} > multi-nav-content {
        overflow: hidden;
        ${this._pageType === PageType.Content ? 'width: 100%;' : ''}
        ${this._pageType === PageType.Navbar ? 'display: none;' : ''}
        ${this._pageType === PageType.None ? `min-width: ${this._minContentWidth}px;` : ''}
      }
    `;

    this._styleElement = style;
    document.head.appendChild(style);
  }
}

if (!customElements.get('multi-nav-container')) {
  customElements.define('multi-nav-container', NavigationComponent);
}